#include "fileexchange.h"

class Client
{
public:
    struct sockaddr_in addr;
    char* buffer;
    int info_size;

    Client()
    {
        buffer = 0;
    }
};


int main( int argc, char *argv[] )
{
    int ret;
    char msg_type;
    struct sockaddr_in addr_inet;
    struct sockaddr_in addr_last;
    unsigned int len_inet;
    int sock;
    char* dgram; // buffer
    int num_clients = 0;
    Client client_list[2];
    char size_msg[5];              // msg with the size of INFO_MSG
    int info_size;                 // size of INFO_MSG

    // Criando socket
    sock = socket( AF_INET, SOCK_DGRAM, 0 );
    if ( sock == -1 )
    {
        std::cout << "Erro no socket!" << std::endl;
        return 1;
    }

    // Criando endereço socket para usar com o bind
    memset( &addr_inet , 0 , sizeof( addr_inet ) );
    addr_inet.sin_family = AF_INET;
    addr_inet.sin_port = htons( 9000 );
    addr_inet.sin_addr.s_addr = INADDR_ANY;

    len_inet = sizeof( addr_inet );

    // BIND
    ret = bind( sock, (struct sockaddr *)&addr_inet, len_inet );
    if( ret == -1 )
    {
        std::cout << "Erro no bind!" << std::endl;
        return 1;
    }

    bool error;

    while( true )
    {
        delete [] client_list[0].buffer;
        delete [] client_list[1].buffer;
        client_list[0].buffer = 0;
        client_list[1].buffer = 0;

        error = false;

        // Aguardando pelos clientes
        std::cout << "Aguardando clientes..." << std::endl;

        len_inet = sizeof( addr_last );

        // Receber HELLO_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            ret = recvfrom( sock, &msg_type, sizeof(char), 0, (struct sockaddr *)&addr_last , &len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no recvfrom" << std::endl;
                error = true;
                break;
            }
            if( msg_type != HELLO_MSG )
            {
                std::cout << "Erro no recebimento de HELLO_MSG!" << std::endl;
                error = true;
                break;
            }
            memcpy( &client_list[i].addr, &addr_last, len_inet );
            std::cout << "HELLO_MSG recebido de " << inet_ntoa( addr_last.sin_addr ) << std::endl;
        }
        if( error ) continue;

        // Mandar ACK_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            msg_type = ACK_MSG;
            ret = sendto( sock, &msg_type, sizeof(char) , 0 , (struct sockaddr *)&client_list[i].addr , len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no sendto!" << std::endl;
                error = true;
                break;
            }
        }
        if( error ) continue;

        // Receber SIZE_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            ret = recvfrom( sock, &size_msg, sizeof(size_msg), 0, (struct sockaddr *)&addr_last , &len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no recvfrom" << std::endl;
                error = true;
                break;
            }
            if( size_msg[0] != SIZE_MSG )
            {
                std::cout << "Erro no recebimento de SIZE_MSG!" << std::endl;
                error = true;
                break;
            }
            memcpy( &info_size, &size_msg[1], sizeof(int) );

            if( memcmp( &client_list[0].addr, &addr_last, len_inet ) == 0 )
            {
                client_list[0].buffer = new char[info_size];
                client_list[0].info_size = info_size;
            }
            else
            {
                client_list[1].buffer = new char[info_size];
                client_list[1].info_size = info_size;
            }
        }
        if( error ) continue;

        // Mandar ACK_MSG e Receber INFO_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            msg_type = ACK_MSG;
            ret = sendto( sock, &msg_type, sizeof(char) , 0 , (struct sockaddr *)&client_list[i].addr , len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no sendto!" << std::endl;
                error = true;
                break;
            }

            ret = recvfrom( sock, client_list[i].buffer, client_list[i].info_size, 0, (struct sockaddr *)&addr_last , &len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no recvfrom" << std::endl;
                error = true;
                break;
            }
            if( client_list[i].buffer[0] != INFO_MSG )
            {
                std::cout << "Erro no recebimento de INFO_MSG!" << std::endl;
                error = true;
                break;
            }
        }
        if( error ) continue;

        // Mandar SIZE_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            size_msg[0] = SIZE_MSG;
            info_size = client_list[i].info_size;
            memcpy( &size_msg[1], &info_size, sizeof(int) );
            ret = sendto( sock, size_msg, sizeof(size_msg) , 0 , (struct sockaddr *)&client_list[(i+1)%2].addr , len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no sendto!" << std::endl;
                error = true;
                break;
            }
        }
        if( error ) continue;

        // Receber ACK_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            ret = recvfrom( sock, &msg_type, sizeof(char), 0, (struct sockaddr *)&addr_last , &len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no recvfrom!" << std::endl;
                error = true;
                break;
            }
            if( msg_type != ACK_MSG )
            {
                std::cout << "Erro no recebimento de ACK_MSG!" << std::endl;
                error = true;
                break;
            }
        }
        if( error ) continue;

        // Mandar INFO_MSG
        for( unsigned int i = 0; i < 2; i++ )
        {
            ret = sendto( sock, client_list[i].buffer, client_list[i].info_size , 0 , (struct sockaddr *)&client_list[(i+1)%2].addr , len_inet );
            if( ret < 0 )
            {
                std::cout << "Erro no sendto!" << std::endl;
                error = true;
                break;
            }
        }
        if( error ) continue;
    }

    // Fechando o socket e saindo
    close(sock);
    return 0;
}
